/**
 * Component Vegas based on Vegas by Jay Salvat (http://jaysalvat.com/)
 * Original code https://github.com/jaysalvat/vegas
 * MIT License, Copyright 2018 Jay Salvat
 *
 * Adaptation for Metro UI by Serhii Pimenov,
 * Copyright 2020 Serhii Pimenov
 */

((Metro, $) => {
    // biome-ignore lint/suspicious/noRedundantUseStrict: <explanation>
    "use strict";

    let VegasDefaultConfig = {
        duration: 4000,
        animationDuration: null,
        transitionDuration: null,
        transition: "fade",
        animation: null,
        slides: [],
        shuffle: false,
        align: "center",
        valign: "center",
        loop: true,
        autoplay: true,
        mute: true,
        cover: true,
        preload: true,
        timer: true,
        overlay: 2,
        color: null,
        volume: 1,
        onPlay: Metro.noop,
        onPause: Metro.noop,
        onEnd: Metro.noop,
        onWalk: Metro.noop,
        onNext: Metro.noop,
        onPrev: Metro.noop,
        onJump: Metro.noop,
        onVegasCreate: Metro.noop,
    };

    Metro.vegasSetup = (options) => {
        VegasDefaultConfig = $.extend({}, VegasDefaultConfig, options);
    };

    if (typeof globalThis.metroVegasSetup !== "undefined") {
        Metro.vegasSetup(globalThis.metroVegasSetup);
    }

    Metro.Component("vegas", {
        videoCache: {},

        init: function (options, elem) {
            this.transitions = [
                "fade",
                "fade2",
                "slideLeft",
                "slideLeft2",
                "slideRight",
                "slideRight2",
                "slideUp",
                "slideUp2",
                "slideDown",
                "slideDown2",
                "zoomIn",
                "zoomIn2",
                "zoomOut",
                "zoomOut2",
                "swirlLeft",
                "swirlLeft2",
                "swirlRight",
                "swirlRight2",
            ];
            this.animations = [
                "kenburns",
                "kenburnsUp",
                "kenburnsDown",
                "kenburnsRight",
                "kenburnsLeft",
                "kenburnsUpLeft",
                "kenburnsUpRight",
                "kenburnsDownLeft",
                "kenburnsDownRight",
            ];

            this.support = {
                objectFit: "objectFit" in document.body.style,
                video: !/(Android|webOS|Phone|iPad|iPod|BlackBerry|Windows Phone)/i.test(navigator.userAgent),
            };

            this._super(elem, options, VegasDefaultConfig, {
                slide: 0,
                slides: null,
                total: 0,
                noshow: false,
                paused: false,
                ended: false,
                timer: null,
                overlay: null,
                first: true,
                timeout: false,
            });

            return this;
        },

        _create: function () {
            const element = this.element;
            const o = this.options;

            this.slides = Metro.utils.isObject(o.slides) || [];
            this.total = this.slides.length;
            this.noshow = this.total < 2;
            this.paused = !o.autoplay || this.noshow;

            if (o.shuffle) {
                this.slides.shuffle();
            }

            if (o.preload) {
                this._preload();
            }

            this._createStructure();
            this._createEvents();

            this._fireEvent("vegas-create", {
                element: element,
            });
        },

        _createStructure: function () {
            const element = this.element;
            const o = this.options;
            const isBody = element[0].tagName === "BODY";
            let wrapper;

            if (!isBody) {
                element.css("height", element.css("height")); // it is not clear why this line

                wrapper = $('<div class="vegas-wrapper">')
                    .css("overflow", element.css("overflow"))
                    .css("padding", element.css("padding"));

                if (!element.css("padding")) {
                    wrapper
                        .css("padding-top", element.css("padding-top"))
                        .css("padding-bottom", element.css("padding-bottom"))
                        .css("padding-left", element.css("padding-left"))
                        .css("padding-right", element.css("padding-right"));
                }

                element.children().appendTo(wrapper);
                element.clear();
            }

            element.addClass("vegas-container");

            if (!isBody) {
                element.append(wrapper);
            }

            if (o.timer) {
                this.timer = $('<div class="vegas-timer"><div class="vegas-timer-progress">');
                element.append(this.timer);
            }

            if (o.overlay) {
                this.overlay = $('<div class="vegas-overlay">').addClass(
                    `overlay${typeof o.overlay === "boolean" || isNaN(o.overlay) ? 2 : +o.overlay}`,
                );
                element.append(this.overlay);
            }

            setTimeout(() => {
                Metro.utils.exec(o.onPlay, null, element[0]);
                this._goto(this.slide);
            }, 1);
        },

        _createEvents: () => {},

        _preload: function () {
            let img;
            let i;

            for (i = 0; i < this.slides.length; i++) {
                const obj = this.slides[i];

                if (obj.src) {
                    img = new Image();
                    img.src = this.slides[i].src;
                }

                if (obj.video) {
                    if (Array.isArray(obj.video)) {
                        this._video(obj.video);
                    } else {
                        this._video(obj.video.src);
                    }
                }
            }
        },

        _slideShow: function () {
            const o = this.options;

            if (this.total > 1 && !this.ended && !this.paused && !this.noshow) {
                this.timeout = setTimeout(() => {
                    this.next();
                }, o.duration);
            }
        },

        _timer: function (state) {
            const o = this.options;

            clearTimeout(this.timeout);

            if (!this.timer) {
                return;
            }

            this.timer.removeClass("vegas-timer-running").find("div").css("transition-duration", "0ms");

            if (this.ended || this.paused || this.noshow) {
                return;
            }

            if (state) {
                setTimeout(() => {
                    this.timer
                        .addClass("vegas-timer-running")
                        .find("div")
                        .css("transition-duration", `${+o.duration - 100}ms`);
                }, 100);
            }
        },

        _fadeSoundIn: function (video, duration) {
            const o = this.options;

            $.animate({
                el: video,
                draw: {
                    volume: +o.volume,
                },
                dur: duration,
            });
        },

        _fadeSoundOut: (video, duration) => {
            $.animate({
                el: video,
                draw: {
                    volume: 0,
                },
                dur: duration,
            });
        },

        _video: function (sources) {
            let source;
            const cacheKey = sources.toString();
            const srcArray = Array.isArray(sources) ? sources : [sources];

            if (this.videoCache[cacheKey]) {
                return this.videoCache[cacheKey];
            }

            const video = document.createElement("video");

            // TODO: check it
            video.preload = true;

            for (const src of srcArray) {
                source = document.createElement("source");
                source.src = src;
                video.appendChild(source);
            }

            this.videoCache[cacheKey] = video;

            return video;
        },

        _goto: function (n) {
            const that = this;
            const element = this.element;
            const o = this.options;
            let _n = n;

            if (typeof this.slides[_n] === "undefined") {
                _n = 0;
            }

            this.slide = _n;

            let $slide;
            let $inner;
            let video;
            let img;
            let $video;
            const slides = element.children(".vegas-slide");
            const obj = this.slides[n];
            let cover = o.cover;
            let transition;
            let animation;
            let transitionDuration;
            let animationDuration;

            if (this.first) {
                this.first = false;
            }

            if (cover !== "repeat") {
                if (cover === true) {
                    cover = "cover";
                } else if (cover === false) {
                    cover = "contain";
                }
            }

            if (o.transition === "random") {
                transition = $.random(this.transitions);
            } else {
                transition = o.transition ? o.transition : this.transitions[0];
            }

            if (o.animation === "random") {
                animation = $.random(this.animations);
            } else {
                animation = o.animation ? o.animation : this.animations[0];
            }

            if (!o.transitionDuration) {
                transitionDuration = +o.duration;
            } else if (o.transitionDuration === "auto" || +o.transitionDuration > +o.duration) {
                transitionDuration = +o.duration;
            } else {
                transitionDuration = +o.transitionDuration;
            }

            if (!o.animationDuration) {
                animationDuration = +o.duration;
            } else if (o.animationDuration === "auto" || +o.animationDuration > +o.duration) {
                animationDuration = +o.duration;
            } else {
                animationDuration = +o.animationDuration;
            }

            $slide = $("<div>").addClass("vegas-slide").addClass(`vegas-transition-${transition}`);

            if (this.support.video && obj.video) {
                video = Array.isArray(obj.video) ? this._video(obj.video) : this._video(obj.video.src);
                video.loop = obj.video.loop ? obj.video.loop : o.loop;
                video.muted = obj.video.mute ? obj.video.mute : o.mute;

                if (!video.muted) {
                    this._fadeSoundIn(video, transitionDuration);
                } else {
                    video.pause();
                }

                $video = $(video)
                    .addClass("vegas-video")
                    .css("background-color", o.color || "#000000");

                if (this.support.objectFit) {
                    $video
                        .css("object-position", `${o.align} ${o.valign}`)
                        .css("object-fit", cover)
                        .css("width", "100%")
                        .css("height", "100%");
                } else if (cover === "contain") {
                    $video.css("width", "100%").css("height", "100%");
                }

                $slide.append($video);
            } else {
                img = new Image();
                $inner = $("<div>")
                    .addClass("vegas-slide-inner")
                    .css({
                        backgroundImage: `url("${obj.src}")`,
                        backgroundColor: o.color || "#000000",
                        backgroundPosition: `${o.align} ${o.valign}`,
                    });

                if (cover === "repeat") {
                    $inner.css("background-repeat", "repeat");
                } else {
                    $inner.css("background-size", cover);
                }

                if (animation) {
                    $inner.addClass(`vegas-animation-${animation}`).css("animation-duration", `${animationDuration}ms`);
                }

                $slide.append($inner);
            }

            if (slides.length) {
                slides.eq(slides.length - 1).after($slide);
            } else {
                element.prepend($slide);
            }

            slides.css("transition", "all 0ms").each(function () {
                this.className = "vegas-slide";

                if (this.tagName === "VIDEO") {
                    this.className += " vegas-video";
                }

                if (transition) {
                    this.className += ` vegas-transition-${transition}`;
                    this.className += ` vegas-transition-${transition}-in`;
                }
            });

            this._timer(false);

            function go() {
                that._timer(true);
                setTimeout(() => {
                    slides
                        .css("transition", `all ${transitionDuration}ms`)
                        .addClass(`vegas-transition-${transition}-out`);

                    slides.each(() => {
                        const video = slides.find("video").get(0);

                        if (video) {
                            video.volume = 1;
                            that._fadeSoundOut(video, transitionDuration);
                        }
                    });

                    $slide
                        .css("transition", `all ${transitionDuration}ms`)
                        .addClass(`vegas-transition-${transition}-in`);

                    for (let i = 0; i < slides.length - 1; i++) {
                        slides.eq(i).remove();
                    }

                    that._fireEvent("walk", {
                        slide: that.current(true),
                    });

                    that._slideShow();
                }, 100);
            }

            if (video) {
                if (video.readyState === 4) {
                    video.currentTime = 0;
                }

                video.play();
                go();
            } else {
                img.src = obj.src;

                if (img.complete) {
                    go();
                } else {
                    img.onload = go;
                }
            }
        },

        _end: function () {
            this.ended = this.options.autoplay;
            this._timer(false);

            this._fireEvent("end", {
                slide: this.current(true),
            });
        },

        play: function () {
            if (!this.paused) {
                return;
            }

            this._fireEvent("play", {
                slide: this.current(true),
            });

            this.paused = false;
            this.next();
        },

        pause: function () {
            this._timer(false);
            this.paused = true;

            this._fireEvent("pause", {
                slide: this.current(true),
            });
        },

        toggle: function () {
            this.paused ? this.play() : this.pause();
        },

        playing: function () {
            return !this.paused && !this.noshow;
        },

        current: function (advanced) {
            if (advanced) {
                return {
                    slide: this.slide,
                    data: this.slides[this.slide],
                };
            }
            return this.slide;
        },

        jump: function (n) {
            if (n <= 0 || n > this.slides.length || n === this.slide + 1) {
                return this;
            }

            this.slide = n - 1;

            this._fireEvent("jump", {
                slide: this.current(true),
            });

            this._goto(this.slide);
        },

        next: function () {
            const o = this.options;

            this.slide++;

            if (this.slide >= this.slides.length) {
                if (!o.loop) {
                    return this._end();
                }

                this.slide = 0;
            }

            this._fireEvent("next", {
                slide: this.current(true),
            });

            this._goto(this.slide);
        },

        prev: function () {
            const o = this.options;

            this.slide--;

            if (this.slide < 0) {
                if (!o.loop) {
                    this.slide++;
                    return this._end();
                }

                this.slide = this.slides.length - 1;
            }

            this._fireEvent("prev", {
                slide: this.current(true),
            });

            this._goto(this.slide);
        },

        changeAttribute: function (attr) {
            const element = this.element;
            const o = this.options;
            const propName = Str.camelCase(attr.replace("data-", ""));

            if (propName === "slides") {
                o.slides = element.attr("data-slides");
                this.slides = Metro.utils.isObject(o.slides) || [];
                this.total = this.slides.length;
                this.noshow = this.total < 2;
                this.paused = !this.options.autoplay || this.noshow;
            } else {
                if (typeof VegasDefaultConfig[propName] !== "undefined") o[propName] = JSON.parse(element.attr(attr));
            }
        },

        destroy: function () {
            const element = this.element;
            const o = this.options;

            clearTimeout(this.timeout);
            element.removeClass("vegas-container");
            element.find("> .vegas-slide").remove();
            element.find("> .vegas-wrapper").children().appendTo(element);
            element.find("> .vegas-wrapper").remove();

            if (o.timer) {
                this.timer.remove();
            }

            if (o.overlay) {
                this.overlay.remove();
            }

            element.remove();
        },
    });
})(Metro, Dom);
